from django.shortcuts import render_to_response
from django.core.context_processors import csrf
from django.contrib.auth.models import User
from django import forms
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from checkin.models import Event
from social.models import UsageProfile, UsageProfileSettings
from datetime import datetime
from datetime import timedelta
try:
	import cPickle as pickle
except:
	import pickle
import base64
from django.forms.widgets import RadioFieldRenderer, RadioInput
from django.utils.encoding import StrAndUnicode, force_unicode
from django.utils.safestring import mark_safe
from django.utils import simplejson
from django.http import HttpResponse

SEARCH_TYPES = [('People Like You',''), ('Search by Time','search')]

class MyRadioInput(RadioInput):
    """
    An object used by RadioFieldRenderer that represents a single
    <input type='radio'>.
    """

    def __unicode__(self):
        return mark_safe(u'%s' % (self.tag(),))

class MyRadioRenderer(RadioFieldRenderer):
    def render(self):
        """Outputs a <td> for this set of radio fields."""
        return mark_safe(u'\n'.join([u'<td class="qcol">%s</td>'
                % force_unicode(w) for w in self]))

    def __iter__(self):
        for i, choice in enumerate(self.choices):
            yield MyRadioInput(self.name, self.value, self.attrs.copy(), choice, i)

#The number of weeks to use when generating a profile.
max_weeks = 4

def getBlankProfile():
	profile = []
	for i in range(7 * 24):
		profile.append(0.0)
	return profile

#Gets the number of weeks represented by a profile if the number is less than max_weeks
def getNumWeeksRepresented(check_ins):
	global weeks
	if len(check_ins) > 0:
		dt = check_ins[0].timestamp
		td = datetime.now() - dt
		days = td.days
		weeks = (days/7) + 1
		if weeks < max_weeks:
			return weeks
		else:
			return max_weeks

def generateUsageProfile(user):
	check_ins = Event.objects.filter(user=user, eventType='I', timestamp__gt = datetime.now() - timedelta(weeks=max_weeks)).order_by('timestamp')
	profile = getBlankProfile()
	weeks = getNumWeeksRepresented(check_ins)
	for check_in in check_ins:
		#Getting date info
		dt = check_in.timestamp
		weekday = dt.weekday()
		time = dt.time()
		hour = time.hour
		minute = time.minute
		week_hour = (weekday * 24) + hour
		#Populating the profile
		profile[week_hour] += 1.0/weeks
		if profile[week_hour] > 1.0: profile[week_hour] = 1.0
		if minute > 29:
			if week_hour+1 < 7 * 24:
				profile[week_hour+1] += 1.0/weeks
				if profile[week_hour+1] > 1.0: profile[week_hour+1] = 1.0
			else:
				profile[0] += 1.0/weeks
				if profile[0] > 1.0: profile[0] = 1.0
	return profile

def saveUsageProfile(user, usage_profile):
	profile_string = base64.b64encode(pickle.dumps(usage_profile))
	try:
		profile = UsageProfile.objects.get(user=user)
		profile.pickle = profile_string
		profile.timestamp = datetime.now()
		profile.save()

	except UsageProfile.DoesNotExist:
		profile = UsageProfile(user=user, pickle=profile_string)
		profile.save()

def getUsageProfile(user):
	usage_profile = []
	try:
		profile = UsageProfile.objects.get(user=user)
		td = datetime.now() - profile.timestamp
		minutes_old = td.seconds / 60
		#If the profile is more than a day old, regenerate and save
		if minutes_old > 60:
			usage_profile = generateUsageProfile(user)
			saveUsageProfile(user, usage_profile)
		else:
			usage_profile = pickle.loads(base64.b64decode(profile.pickle))
	#If the profile does not exist, regenerate and save
	except UsageProfile.DoesNotExist:
		usage_profile = generateUsageProfile(user)
		saveUsageProfile(user, usage_profile)
	return usage_profile


def getHeatmap(user=None):
	users = User.objects.filter()
	if(user):
		users = users.filter(pk=user.pk)
	usages = []
	
	#Collect usages for all users
	for user in users:
		usages.append(getUsageProfile(user))
	
	usageMap = []
	
	for i in range(168):
		#Average all user usages
		totalUsage = 0.0
		numUsages = 0
		for usage in usages:
			totalUsage += usage[i]
			numUsages += 1
		avgUsage = totalUsage / numUsages
		usageMap.append((i, avgUsage))
	
	#Normalize usageMap
	maxUsage = max(usageMap, key=lambda x: x[1])
	for key,value in usageMap:
		if maxUsage[1] == 0:
			usageMap[key] = (key, 0)
		else:
			usageMap[key] = (key, value / maxUsage[1])
	
	return usageMap


def generateComparedHeatmap(profile_1, profile_2):
	profile = []
	max = 0.0
	for i in range(7*24):
		combined = profile_1[i] * profile_2[i]
		if combined > max:
			max = combined
		profile.append(combined)
	heatmap = []
	for i in range(7*24):
		profile[i] = profile[i]/max
		heatmap.append( (i, profile[i]))
    
	return heatmap

def compareProfiles(profile_1, profile_2):
	tally = 0
	for i in range(7*24):
		tally += profile_1[i] * profile_2[i]
	return tally

def usageSearch(searching_profile, searching_id):
	unsorted_results = []
	users = User.objects.all()
	for user in users:
	    	searching_settings = UsageProfileSettings.objects.get_or_create(user=user)[0]
		if not user.id == searching_id and user.profile.public and searching_settings.partner:
			temp_profile = getUsageProfile(user)
			score = int(compareProfiles(searching_profile, temp_profile) * 100)
			if not score == 0:
			    full_name = user.first_name + " " + user.last_name
			    unsorted_results.append({"score":score,"name":full_name, "id":user.id})
	sorted_results = sorted(unsorted_results, key=lambda k: k['score'], reverse=True)
	return sorted_results

@login_required(login_url='/accounts/login/')
def viewSimilar(request):
	user = request.user
	usagesettings = UsageProfileSettings.objects.get_or_create(user=user)[0]
	if usagesettings.partner:
		searching_profile = getUsageProfile(user)
		results = usageSearch(searching_profile, user.id)
		return render_to_response("social/similarity.html", {'types':SEARCH_TYPES, 'type':'', 'results': results}, context_instance=RequestContext(request))
	else:
		return render_to_response("message.html", {'message':'Error: You must opt-in to the partner search to use this feature. You can do so <a href="/userprofile/privacy/">here</a>.'}, context_instance=RequestContext(request))


@login_required(login_url='/accounts/login/')
def compareUsage(request, comparing_id):
	#user = request.user
	#user_usage = getUsageProfile(user)
	comparing = User.objects.get(pk=comparing_id)
	usagesettings = UsageProfileSettings.objects.get_or_create(user=comparing)[0]
	if usagesettings.public:
		#comparing_usage = getUsageProfile(comparing)
		comparing_name = comparing.first_name + " " + comparing.last_name
		#heatmap = generateComparedHeatmap(user_usage, comparing_usage)
		heatmap = getHeatmap(user=request.user)
		compareMap = getHeatmap(user=comparing)
		return render_to_response("social/compare.html", {'usageMap':heatmap, 'compareMap':compareMap, 'comparing_name': comparing_name}, context_instance=RequestContext(request))
	else:
		return render_to_response("message.html", {'message':'Error: The user that you are attempting to compare with is not sharing their usage information.'}, context_instance=RequestContext(request))

TIMES = ((-1, 'None'),
	    (0,'12 AM'),
	    (1,'1 AM'),
	    (2,'2 AM'),
	    (3,'3 AM'),
	    (4,'4 AM'),
	    (5,'5 AM'),
	    (6,'6 AM'),
	    (7,'7 AM'),
	    (8,'8 AM'),
	    (9,'9 AM'),
	    (10,'10 AM'),
	    (11,'11 AM'),
	    (12,'12 PM'),
	    (13,'1 PM'),
	    (14,'2 PM'),
	    (15,'3 PM'),
	    (16,'4 PM'),
	    (17,'5 PM'),
	    (18,'6 PM'),
	    (19,'7 PM'),
	    (20,'8 PM'),
	    (21,'9 PM'),
	    (22,'10 PM'),
	    (23,'11 PM'),
	    )

class TimeForm(forms.Form):
    mon = forms.ChoiceField(initial=-1,label="Monday",choices=TIMES,widget=forms.RadioSelect(renderer=MyRadioRenderer))
    tues = forms.ChoiceField(initial=-1,label="Tuesday",choices=TIMES,widget=forms.RadioSelect(renderer=MyRadioRenderer))
    weds = forms.ChoiceField(initial=-1,label="Wednesday",choices=TIMES,widget=forms.RadioSelect(renderer=MyRadioRenderer))
    thurs = forms.ChoiceField(initial=-1,label="Thursday",choices=TIMES,widget=forms.RadioSelect(renderer=MyRadioRenderer))
    fri = forms.ChoiceField(initial=-1,label="Friday",choices=TIMES,widget=forms.RadioSelect(renderer=MyRadioRenderer))
    sat = forms.ChoiceField(initial=-1,label="Saturday",choices=TIMES,widget=forms.RadioSelect(renderer=MyRadioRenderer))
    sun = forms.ChoiceField(initial=-1,label="Sunday",choices=TIMES,widget=forms.RadioSelect(renderer=MyRadioRenderer))

    def getUsageProfile(self):
	data = self.cleaned_data
	profile = getBlankProfile()
	if not data["mon"] == -1:
	        profile[int(data["mon"])] += 1
	if not data["tues"] == -1:
	        profile[int(data["tues"])+24] += 1
	if not data["weds"] == -1:
		profile[int(data["weds"])+(24*2)] += 1
	if not data["thurs"] == -1:
		profile[int(data["thurs"])+(24*3)] += 1
	if not data["fri"] == -1:
	    	profile[int(data["fri"])+(24*4)] += 1
	if not data["sat"] == -1:
	        profile[int(data["sat"])+(24*5)] += 1
	if not data["sun"] == -1:
		profile[int(data["sun"])+(24*6)] += 1
	return profile

def renderUsageSearch(request):
	searching_profile = getBlankProfile()
	user = request.user
	usagesettings = UsageProfileSettings.objects.get_or_create(user=user)[0]
	if usagesettings.partner:
		heatmap = []
		selected = -1

		#Retrieve the usage profile from POST
		form = 1
		if request.POST:
			form = request.POST
			for key in form:
				if key == "selected":
					selected = form["selected"]
				if key != "csrfmiddlewaretoken" and key != "selected":
					value = request.POST[key]
					searching_profile[int(key)] = float(value)
					heatmap.append((int(key), float(value)))

		results = usageSearch(searching_profile, user.id)

		return render_to_response("social/similarity.html", {'types':SEARCH_TYPES, 'type':'search', 'results': results, 'form':form, 'usageMap':heatmap, 'times':TIMES, 'selected':selected}, context_instance=RequestContext(request))
	else:
		return render_to_response("message.html", {'message':'Error: You must opt-in to the partner search to use this feature. You can do so <a href="/userprofile/privacy/">here</a>.'}, context_instance=RequestContext(request))

def compareHeatmapRequest(request):
	comparing = User.objects.get(id=request.GET.get('user'))
	comparing_name = comparing.first_name + " " + comparing.last_name
	heatmap = getHeatmap(user=request.user)
	compareMap = getHeatmap(user=comparing)
	
	mapValues = {'user':[], 'compare':[], 'compareName':comparing_name}
	for hour,value in heatmap:
		mapValues['user'].append({'hour':hour, 'value':value})
	for hour,value in compareMap:
		mapValues['compare'].append({'hour':hour, 'value':value})
	data = simplejson.dumps(mapValues, indent=4)
	
	return HttpResponse(data, mimetype="application/javascript")
	
